
/*
  小程序混入 Mixins  参考 vue2  使用方法相同
    支持 Page | Component 构造器
    支持 deep多层级混入
  1. 修改合并机制，改为深度合并
  2. 2020/4/48
    在全局混入 computed 计算机制
    整合 computed 到全局 mixins函数
  3. 2021/04/09
    深度混入
    描述： 完成 page A混入 B， B又混入 c ... 等这种多层级混入的机制
  4. 2021/04/24
    component 混入功能开启  同时 component 混入  computed 计算属性  方法同Page构造器一样
  5. 2021/09/17
    混入页面或者component 实例-方法  两者互相兼容  ###  定义方法( 页面方法定义在根对象上,component 定义在methods里 )
  6. 2022/8/31
    加入全局  page component watch
    优化 computed watch 在component 构造器上的性能与架构
  */

const comUtil = require('@/utils/common')
const moduleConfig = require('../config')
const mixinConfig = require('./config')
const computedConfig = require('../computed/config')
const watchConfig = require('../watch/config')

// 页面混入
const lifecycle_Page = ['onLoad', 'onReady', 'onShow', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage', 'onPageScroll']

// 递归收集 mixin
function getDeepMixins(mixConfig, deepArr) {
  const childMixin = mixConfig.mixins
  if (comUtil.isType(childMixin, 'Array') && childMixin.length !== 0) {
    deepArr.push(...childMixin)
    childMixin.forEach(childMixinConfig => {
      getDeepMixins(childMixinConfig, deepArr)
    })
  }
  return deepArr
}
const nativePage = Page
Page = function(config) {
  // 全局混入开启关闭
  if (moduleConfig.openGlobalMixin_page) {
    let mixinsDeep = []
    // 收集子 mixin
    mixinsDeep = getDeepMixins(config, mixinsDeep)
    // 加入全局mixin
    if (mixinConfig.globalMixins_page) {
      mixinsDeep.unshift(mixinConfig.globalMixins_page)
    }
    _mixin_extend(mixinsDeep, config)
  }
  return nativePage(config)
}

// 组件混入
const lifecycle_Component = ['created', 'attached', 'ready', 'moved', 'detached', 'error']

// 组件全局  mixins computed

const nativeComponent = Component
Component = function(config) {
  if (moduleConfig.openGlobalMixin_component) {
    let mixinsDeep = []
    // 收集子 mixin
    mixinsDeep = getDeepMixins(config, mixinsDeep)
    // 加入全局mixin
    if (mixinConfig.globalMixins_component) {
      mixinsDeep.unshift(mixinConfig.globalMixins_component)
    }
    _mixin_extend(mixinsDeep, config, false)
    // 组件 compued 二次处理 config
    const compuedOption = config[computedConfig.computedKey_page]
    if (compuedOption && comUtil.isType(compuedOption, 'Object')) {
      config.data[computedConfig.computedKey_component] = compuedOption
    }
    // 组件 watch 二次处理 config
    const watchOption = config[watchConfig.watchKey_page]
    if (watchOption && comUtil.isType(watchOption, 'Object')) {
      config.data[watchConfig.watchKey_component] = watchOption
    }
  }
  return nativeComponent(config)
}

/*
 合并函数
  对特殊属性  data computed 进行深度合并
  对生命周期函数 onload onReady  合并在当前路由生命周期内
  对自定义方法  进行浅合并
  _mixin_extend(mixins:Object,config:Object , isPage:Boolean);
*/
// 页面 组件  共有合并关键字
const public_mergeKeys = [
  'data',
  computedConfig.computedKey_page,
  watchConfig.watchKey_page
]
// 组件合并关键字
const component_mergeKeys = [
  'behaviors',
  'properties',
  'lifetimes',
  'methods',
  'options'
]
// 针对 对象 或者 数组的合并
function _mixin_merge(config, mixin, key) {
  if (config[key] === undefined) {
    config[key] = mixin[key]
  } else {
    comUtil.mixin(config[key], mixin[key])
  }
}
// 继承
function _mixin_extend(mixins, config, isPage = true) {
  let _lifecycle
  if (isPage) {
    _lifecycle = lifecycle_Page
  } else {
    _lifecycle = lifecycle_Component
  }
  mixins.forEach(mixin => {
    if (comUtil.isType(mixin, 'Object')) {
      Object.keys(mixin).forEach(key => {
        // 合并 页面或者 组件 data, computed
        if (public_mergeKeys.includes(key)) {
          _mixin_merge(config, mixin, key)
          // 合并 页面或者 组件 生命周期
        } else if (_lifecycle.includes(key)) {
          const nativeLifecycle = config[key]
          if (nativeLifecycle) {
            config[key] = function() {
              const arg = Array.prototype.slice.call(arguments)
              mixin[key].apply(this, arg)
              return nativeLifecycle && nativeLifecycle.apply(this, arg)
            }
          } else {
            config[key] = mixin[key]
          }
          /* 页面 或者 组件 方法混入 */
        } else {
          // 页面方法混入
          if (isPage) {
            // 排除组件关键字于生命周期
            if (!lifecycle_Component.includes(key)) {
              if (config[key] === undefined) {
                if (key !== 'methods') {
                  config[key] = mixin[key]
                } else {
                  // 对组件实例methods进行方法合并
                  if (comUtil.isType(mixin[key], 'Object')) {
                    comUtil.mixin(config, mixin[key])
                  }
                }
              }
            }
          } else {
            // 组件方法混入
            if (component_mergeKeys.includes(key)) {
              _mixin_merge(config, mixin, key)
            } else {
              // 排除页面关键字与生命周期
              if (!lifecycle_Page.includes(key)) {
                // 判断组件 methods是否定义
                if (!('methods' in config)) {
                  config.methods = {}
                }
                // 组件methods定义且为对象
                // 合并方法
                const { methods: cpt_methods } = config
                if (cpt_methods &&
                  comUtil.isType(cpt_methods, 'Object') &&
                  cpt_methods[key] === undefined
                ) {
                  cpt_methods[key] = mixin[key]
                }
              }
            }
          }
        }
      })
    }
  })
}

